home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOpus Plus
/
DOpus Plus.iso
/
Tutorial
/
C Guide
/
Average_Module1
/
DOExchange.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-10-09
|
36KB
|
908 lines
/*******************************************************************
DOExchange.c
It's a try to do the Exchange work within a dopus popup menu.
Since nothing of the commodities.library is really documented,
this source may be wrong. If you know more, you may change/add
what is to do...
SO BE WARNED... - THIS IS A HACK !!
(even if it seems to be OK)
Initial idea by Jens Weyer.
*********************************************************************/
#include "includes/DOExchange.h"
/********************************************************************/
// some prototypes
ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
register __a1 DOE_Data *dd );
void __saveds New_Proc( void );
void CleanUp( DOE_Data *dd, IPCData *ipc );
BOOL OpenWin( DOE_Data *dd );
void BorderDraw( DOE_Data *dd, BOOL invers );
BOOL InitPopupMenu( DOE_Data *dd );
APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to );
void ClearPopupMenu( DOE_Data *dd );
BOOL DoMenu( DOE_Data *dd );
BOOL HandleWin( DOE_Data *dd );
BOOL HandleCX( DOE_Data *dd );
BOOL HandleNotify( DOE_Data *dd );
BOOL HandleIPC( DOE_Data *dd );
BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to );
BOOL WriteConfig( DOE_Data *dd );
BOOL ReadConfig( DOE_Data *dd );
/********************************************************************/
// it is surely useful to detach here
void DOExchange( STRPTR args, struct Screen *screen, IPCData *ipc )
{
DOE_Data *dd;
FuncArgs *fargs;
if( !exchange )
{
if( (dd = AllocMemH(mempool, sizeof(DOE_Data))) )
{
dd->screen = screen;
dd->a4 = getreg( REG_A4 );
dd->module = (struct Library *) getreg( REG_A6 );
dd->library = DOpusBase;
IPC_Launch( 0,
&exchange, // pointer to pointer to the IPC of the new process, for storing...
"DOpus Exchange", // name of the new process
(ULONG) New_Proc, // entrypoint of the new process
4096, // stack to use
(ULONG) dd, // data to pass to the new process
DOSBase ); // pointer to dos.library
if( !exchange ) // if detaching failed...
{
FreeMemH( dd );
return;
}
}
}
if( args )
{
if( (fargs = ParseArgs(FUNC0_TEMPLATE, args)) )
{
ULONG cmd = 0, counter;
PassData *pd;
for( counter = 0; counter < TEMPLATE_COUNT; counter++ )
if( fargs->FA_Arguments[counter] )
cmd |= 1 << counter;
if( (pd = AllocVec(sizeof(PassData), MEMF_CLEAR)) )
{
pd->FrontPen = ARG_TC ? *(ULONG *) ARG_TC : NULL;
pd->BackPen = ARG_BGC ? *(ULONG *) ARG_BGC : NULL;
pd->name = ARG_NAME ? (STRPTR) ARG_NAME : NULL;
IPC_Command( exchange,
cmd,
NULL,
NULL,
pd, // FreeVec the data automatically
REPLY_NO_PORT );
}
DisposeArgs( fargs );
}
}
}
/********************************************************************/
ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
register __a1 DOE_Data *dd )
{
struct Library *DOpusBase;
putreg( REG_A4, dd->a4 );
dd->ipc = ipc;
DOpusBase = dd->library;
// now follows our initialization
dd->module->lib_OpenCnt++;
// the default button text
dd->itext.IText = DOpusGetString( locale, MSG_TEXT );
dd->itext.FrontPen = 1;
ReadConfig( dd );
if( strlen(dd->name) )
dd->itext.IText = dd->name;
// install our notify
if( !(dd->notify_port = CreateMsgPort()) ||
!(dd->notify_handle = AddNotifyRequest(DN_OPUS_HIDE | DN_OPUS_SHOW | DN_OPUS_QUIT |
DN_CLOSE_WORKBENCH | DN_OPEN_WORKBENCH | DN_RESET_WORKBENCH,
NULL, dd->notify_port)) )
return FALSE;
// fill our newbroker structure
dd->nb.nb_Version = NB_VERSION;
dd->nb.nb_Name = DOpusGetString( locale, FUNC0_DESCRIPTION );
dd->nb.nb_Title = dd->nb.nb_Name;
dd->nb.nb_Descr = DOpusGetString( locale, MSG_CX_DESCR );
dd->nb.nb_Unique = NBU_UNIQUE|NBU_NOTIFY;
dd->nb.nb_Flags = COF_SHOW_HIDE;
// create the broker
if( !(dd->nb.nb_Port = CreateMsgPort()) ||
!(dd->our_cxobj = CxBroker(&dd->nb, (LONG *) &dd->signals)) ||
dd->signals ||
!(dd->sender = CreateMsgPort()) )
return FALSE;
return TRUE; // all was successfully
}
void __saveds New_Proc( void )
{
DOE_Data *dd;
IPCData *ipc;
struct Library *DOpusBase;
if( !(DOpusBase = (struct Library *) FindName(&((struct ExecBase *)*((ULONG *)4))->LibList, "dopus5.library")) )
return;
ipc = IPC_ProcStartup( (ULONG *) &dd, New_Proc_Startup );
putreg( REG_A4, dd->a4 );
if( !ipc )
{
if( dd )
CleanUp( dd, dd->ipc );
return;
}
// make our broker aktive
ActivateCxObj( dd->our_cxobj, TRUE );
// open the window (looks like a dopus button)
if( OpenWin(dd) )
{
while( TRUE )
{
dd->signals = Wait( 1 << dd->sender->mp_SigBit | // reply port of our sended messages
1 << dd->nb.nb_Port->mp_SigBit |
1 << dd->notify_port->mp_SigBit |
1 << dd->ipc->command_port->mp_SigBit | // ipc messages
(dd->win ? 1 << dd->win->UserPort->mp_SigBit : NULL) ); // IDCMP messages
if( dd->signals & 1 << dd->sender->mp_SigBit ) // our message does return
{
while( (dd->fmsg = (FakeMsg *) GetMsg(dd->sender)) )
FreeMemH( dd->fmsg ); // we have only to free the memory
}
dd->stop = FALSE;
if( dd->signals & 1 << dd->nb.nb_Port->mp_SigBit )
{
if( HandleCX(dd) )
break;
}
if( dd->signals & 1 << dd->notify_port->mp_SigBit )
{
if( HandleNotify(dd) )
break;
}
if( dd->signals & 1 << dd->ipc->command_port->mp_SigBit )
{
if( HandleIPC(dd) )
break;
}
if( dd->win && (dd->signals & 1 << dd->win->UserPort->mp_SigBit) )
{
if( HandleWin(dd) )
break;
}
}
}
CleanUp( dd, exchange );
exchange = NULL;
}
void CleanUp( DOE_Data *dd, IPCData *ipc )
{
if( dd->win )
CloseWindow( dd->win );
if( dd->notify_port )
{
if( dd->notify_handle )
RemoveNotifyRequest( dd->notify_handle );
while( !IsMsgPortEmpty( dd->notify_port) )
ReplyFreeMsg( GetMsg(dd->notify_port) );
DeleteMsgPort( dd->notify_port );
}
DeleteCxObjAll( dd->our_cxobj );
if( dd->nb.nb_Port )
{
while( !IsMsgPortEmpty(dd->nb.nb_Port) )
ReplyMsg( GetMsg(dd->nb.nb_Port) );
DeleteMsgPort( dd->nb.nb_Port );
}
if( dd->sender )
{
while( !IsMsgPortEmpty(dd->sender) )
FreeMemH( GetMsg(dd->sender) );
DeleteMsgPort( dd->sender );
}
dd->module->lib_OpenCnt--;
FreeMemH( dd );
IPC_Free( ipc );
}
/********************************************************************/
BOOL OpenWin( DOE_Data *dd )
{
// lock the screen
if( (dd->screen = LockPubScreen(NULL)) )
{
if( (dd->win = OpenWindowTags( NULL,
WA_Left, dd->ibox.Left,
WA_Top, dd->ibox.Top,
WA_Height, dd->screen->Font->ta_YSize + 4,
WA_Width, IntuiTextLength( &dd->itext ) + 5,
WA_Gadgets, &draggadget,
WA_Flags, WFLG_BORDERLESS | WFLG_NEWLOOKMENUS |
WFLG_SMART_REFRESH | WFLG_RMBTRAP,
WA_IDCMP, IDCMP_MOUSEBUTTONS,
WA_AutoAdjust, TRUE,
WA_PubScreen, dd->screen,
WA_ScreenTitle, (STRPTR) ~0,
TAG_DONE)) )
{
// register our window, so it does get messages
// even it is inactive
SetWindowID( dd->win, &dd->id, 0x1400, 0 );
BorderDraw( dd, FALSE );
}
UnlockPubScreen( NULL, dd->screen );
}
return (BOOL) dd->win;
}
void BorderDraw( DOE_Data *dd, BOOL invers )
{
// flood the port with supplied colour
SetRast( dd->win->RPort, dd->itext.BackPen );
// draw a border
SetAPen( dd->win->RPort, invers ? 2 : 1 );
Move( dd->win->RPort, 1, dd->win->Height - 1 );
Draw( dd->win->RPort, dd->win->Width-1, dd->win->Height - 1 );
Draw( dd->win->RPort, dd->win->Width-1, 1 );
SetAPen( dd->win->RPort, invers ? 1 : 2 );
Move( dd->win->RPort, 0, dd->win->Height - 1 );
Draw( dd->win->RPort, 0, 0 );
Draw( dd->win->RPort, dd->win->Width-1, 0 );
// set values for the Rastport
SetRPAttrs( dd->win->RPort,
RPTAG_APen, dd->itext.FrontPen,
RPTAG_BPen, dd->itext.BackPen,
TAG_DONE );
// print the button text
Move( dd->win->RPort, 3, dd->win->RPort->Font->tf_Baseline + 2 );
Text( dd->win->RPort, dd->itext.IText, strlen(dd->itext.IText) );
}
/********************************************************************/
// popup menu work
// do not be worry, most of this things is only needed to allow:
// - unlimited count of entries with their needed submenu
// - easier to do the cleanup
BOOL InitPopupMenu( DOE_Data *dd )
{
dd->entry_count = 0;
// init the lists we need
NewList( (struct List *) &dd->popmenu.item_list );
NewList( (struct List *) &dd->submenus );
// open the popupmenu above our window
dd->popmenu.flags = POPUPMF_ABOVE;
// locale pointer, so we must not supply real strings - only ID's
dd->popmenu.locale = locale;
// since nothing is documented here, I have done what I think:
// all brokers must be anywhere in a list and if we have one
// node (our broker), we can access the whole list...
dd->ptr_node = (struct Node *) dd->our_cxobj;
// the objects does work with interrupts, it may a good idea
// to protect the access to the list with Disable()
Disable();
// go to the head of the list
do
{
dd->ptr_node = dd->ptr_node->ln_Pred;
}
while( dd->ptr_node->ln_Pred->ln_Pred );
// now we can create our needed lists - we have here 2 + X (!)
// first list - MinList with the names of the objects (needed by DoPopUpMenu)
// second list - MinList, each node contain again a MinList (third list)
// this list is only for easy handling for us
// third (and X) list - MinList for submenu, it does also contain a pointer
// to the cx_object
do
{
// this counter is used to give each (main) menu item an ID.
// since these items have all submenus, you may also give
// all the same ID (dopus5.library does only pass them through)
dd->entry_count++;
// now it's time to create the menu entry...
if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
{
dd->popitem->item_name = dd->ptr_node->ln_Name;
dd->popitem->id = dd->entry_count;
// each item has a submenu
if( (dd->popitem->data = CreateSubMenu(dd, MSG_ACTIVATE, MSG_REMOVE)) )
dd->popitem->flags = POPUPF_SUB;
// the next block is a kind of sorted adding of our nodes
// since this are MinList's, it is not possible to use DOpus
// list functions here...
// at first we need a pointer to the first node
dd->compare = (PopUpItem *) dd->popmenu.item_list.mlh_Head;
if( IsListEmpty((struct List *) &dd->popmenu.item_list) ||
Stricmp(dd->popitem->item_name, dd->compare->item_name) < 0 ) // or our new name is lower
{
AddHead( (struct List *) &dd->popmenu.item_list,
(struct Node *) dd->popitem );
}
else
{
// walk through the list until a name is higher than our new name or
// the list is no more entries
while( dd->compare->node.mln_Succ->mln_Succ &&
Stricmp(dd->popitem->item_name, ((PopUpItem *) dd->compare->node.mln_Succ)->item_name) > 0 )
dd->compare = (PopUpItem *) dd->compare->node.mln_Succ;
// insert the new node before (!) the higher name is coming
// or even append it, if no higher entry does exist
Insert( (struct List *) &dd->popmenu.item_list,
(struct Node *) dd->popitem,
(struct Node *) dd->compare );
}
}
}
while( (dd->ptr_node = dd->ptr_node->ln_Succ)->ln_Succ );
// we have not all done now, but we must not access longer the object list,
// so we can allow again all stuff
Enable();
// adding a barlabel
if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
{
dd->popitem->item_name = POPUP_BARLABEL;
dd->popitem->id = 0;
AddTail( (struct List *) &dd->popmenu.item_list,
(struct Node *) dd->popitem );
}
// adding a item to snap the current settings
if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
{
dd->popitem->item_name = (STRPTR) MSG_SAVE_POS;
dd->popitem->id = POPID_SAVE;
dd->popitem->flags = POPUPF_LOCALE;
AddTail( (struct List *) &dd->popmenu.item_list,
(struct Node *) dd->popitem );
}
// and an item to allow to quit directly
if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
{
dd->popitem->item_name = (STRPTR) MSG_QUIT;
dd->popitem->id = POPID_QUIT;
dd->popitem->flags = POPUPF_LOCALE;
AddTail( (struct List *) &dd->popmenu.item_list,
(struct Node *) dd->popitem );
}
return TRUE;
}
// this routine is already prepared to be copied if you need it :)
// you must change only small things then...
APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to )
{
PopUpItem *popitem;
if( (dd->submenu_node = AllocMemH(mempool, sizeof(SubMenu_Node))) )
{
// init the list
NewList( (struct List *) &dd->submenu_node->submenu );
// getting the items to show
for( dd->a4 = from; dd->a4 <= to; dd->a4++ )
{
// allocate a node
if( (popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
{
// fill the node
popitem->item_name = (STRPTR) dd->a4;
popitem->flags = POPUPF_LOCALE;
popitem->id = dd->a4;
popitem->data = dd->ptr_node; // pointer to the CX_object
switch( dd->a4 )
{
case MSG_ACTIVATE :
popitem->flags |= POPUPF_CHECKIT;
// now it is again result of hard work and
// may be wrong... :)
// check the current activation state
//if( ((STRPTR) dd->ptr_node)[0x0E] & 1 << 1 )
if( ((CX_OBJ *) dd->ptr_node)->flags & 1 << 1 )
popitem->flags |= POPUPF_CHECKED;
break;
case MSG_APPEAR :
case MSG_DISAPPEAR:
// checking if this object has a GUI
//if( !(((STRPTR) dd->ptr_node)[0x0E] & 1 << 2) )
if( !(((CX_OBJ *) dd->ptr_node)->flags & 1 << 2) )
popitem->flags |= POPUPF_DISABLED;
}
// add the popitem node to the submenu list
AddTail( (struct List *) &dd->submenu_node->submenu,
(struct Node *) popitem );
}
}
// add the submenu list to the second list, so we can free it later all easily
AddTail( (struct List *) &dd->submenus,
(struct Node *) dd->submenu_node );
return &dd->submenu_node->submenu;
}
return NULL;
}
// this routines should be clear for everyone...
void ClearPopupMenu( DOE_Data *dd )
{
while( !IsListEmpty((struct List *) &dd->popmenu.item_list) )
FreeMemH( RemHead((struct List *) &dd->popmenu.item_list) );
while( !IsListEmpty((struct List *) &dd->submenus) )
{
dd->submenu_node = (SubMenu_Node *) RemHead((struct List *) &dd->submenus);
while( !IsListEmpty((struct List *) &dd->submenu_node->submenu) )
FreeMemH( RemHead((struct List *) &dd->submenu_node->submenu) );
FreeMemH( dd->submenu_node );
}
}
BOOL DoMenu( DOE_Data *dd )
{
// preparing the popupmenu
if( InitPopupMenu(dd) )
{
// start the popupmenu
if( DoPopUpMenu(dd->win, &dd->popmenu, &dd->popitem, MENUDOWN) != -1 )
{
// if the previous call does return, dd->popitem contains the user selection
switch( dd->popitem->id )
{
case POPID_SAVE :
WriteConfig( dd );
break;
case POPID_QUIT :
dd->stop = TRUE;
break;
case MSG_ACTIVATE:
case MSG_APPEAR:
case MSG_DISAPPEAR:
case MSG_REMOVE: // create a fake CxMsg (not documented...)
// and send it to the choosed CxObj
SendCxMsg( (CX_OBJ *) dd->popitem->data, // send it to...
(dd->popitem->id == MSG_ACTIVATE ? (dd->popitem->flags & POPUPF_CHECKED ? CXCMD_ENABLE : CXCMD_DISABLE) : (dd->popitem->id - MSG_ACTIVATE)*2 + 17 ),
dd->sender ); // use this port to reply to
break;
}
}
// free the menu
ClearPopupMenu( dd );
}
return dd->stop;
}
/********************************************************************/
// handling routines
BOOL HandleWin( DOE_Data *dd )
{
while( !dd->stop && (dd->messages = GetMsg(dd->win->UserPort)) )
{
// since we are not interested in other messages, we use a simple "if"
if( ((struct IntuiMessage *) dd->messages)->Class == IDCMP_MOUSEBUTTONS &&
((struct IntuiMessage *) dd->messages)->Code == MENUDOWN )
//&&
//((ULONG) WhichLayer(&dd->screen->LayerInfo, dd->screen->MouseX, dd->screen->MouseY)) == ((ULONG) dd->win->WLayer) )
{
// since we have no real gadget, the window must be activated
// else the popup menu may be in some cases not selectable
ActivateWindow( dd->win );
// make our window "selected"
BorderDraw( dd, TRUE );
dd->stop = DoMenu( dd );
// "unselect"
BorderDraw( dd, FALSE );
// deactivate our window again (will activate the previous
// activated window, if available)
if( dd->win->NextWindow )
ActivateWindow( dd->win->NextWindow );
else
dd->win->Flags ^= WFLG_WINDOWACTIVE;
}
ReplyMsg( dd->messages );
}
return dd->stop;
}
BOOL HandleCX( DOE_Data *dd )
{
while( !dd->stop && (dd->messages = GetMsg(dd->nb.nb_Port)) )
{
// on this place we can use some variables for other work...
dd->a4 = CxMsgType( (CxMsg *) dd->messages );
dd->signals = CxMsgID((CxMsg *) dd->messages);
// should be so fast as possible...
ReplyMsg( dd->messages );
if( dd->a4 == CXM_COMMAND )
{
switch( dd->signals )
{
case CXCMD_DISABLE: // since we are do not handle any
// other things than our window, it
// is a little bit useless to disable/
// enable, but anyway we do it... :)
ActivateCxObj( dd->our_cxobj, FALSE );
break;
case CXCMD_ENABLE:
ActivateCxObj( dd->our_cxobj, TRUE );
break;
case CXCMD_APPEAR:
if( !dd->win )
{
OpenWin( dd );
}
else
WindowToFront( dd->win );
break;
case CXCMD_DISAPPEAR:
if( dd->win )
{
// save our current position temporally
dd->ibox.Left = dd->win->LeftEdge;
dd->ibox.Top = dd->win->TopEdge;
CloseWindow( dd->win );
dd->win = NULL;
}
break;
case CXCMD_KILL:
dd->stop = TRUE;
break;
/* it seems this value needs a special flag in
the newbroker structure and so no messages of
this ID does arrive here...
case CXCMD_LIST_CHG:
break;
*/
}
}
}
return dd->stop;
}
BOOL HandleNotify( DOE_Data *dd )
{
while( !dd->stop && (dd->messages = GetMsg(dd->notify_port)) )
{
switch( ((DOpusNotify *) dd->messages)->dn_Type )
{
case DN_OPUS_QUIT :
dd->stop = TRUE;
break;
case DN_CLOSE_WORKBENCH:
case DN_OPUS_HIDE : // storing our current window state
dd->flags = dd->win ? TRUE : FALSE;
SendCxMsg( (CX_OBJ *) dd->our_cxobj,
CXCMD_DISAPPEAR,
dd->sender );
break;
case DN_OPEN_WORKBENCH:
case DN_RESET_WORKBENCH:
case DN_OPUS_SHOW :
if( dd->flags )
SendCxMsg( (CX_OBJ *) dd->our_cxobj,
CXCMD_APPEAR,
dd->sender );
break;
}
ReplyFreeMsg( dd->messages );
}
return dd->stop;
}
BOOL HandleIPC( DOE_Data *dd )
{
while( !dd->stop && (dd->messages = GetMsg(dd->ipc->command_port)) )
{
if( ((IPCMessage *) dd->messages)->command & IPCCMD_QUIT )
{
dd->stop = TRUE;
}
else
{
if( ((IPCMessage *) dd->messages)->command & IPCCMD_SHOW )
{
SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_APPEAR, dd->sender );
}
if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME )
{
// make a copy...
strncpy( dd->name, ((PassData *) ((IPCMessage *) dd->messages)->data_free)->name, 11 )[11] = 0;
// if the supplied name is empty, it does fallback to the buildin name
dd->itext.IText = strlen(dd->name) ? dd->name : DOpusGetString( locale, MSG_TEXT );
}
if( ((IPCMessage *) dd->messages)->command & IPCCMD_BGC )
{
dd->itext.BackPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->BackPen;
}
if( ((IPCMessage *) dd->messages)->command & IPCCMD_TC )
{
dd->itext.FrontPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->FrontPen;
}
if( dd->win )
{
// save our current position temporally
dd->ibox.Left = dd->win->LeftEdge;
dd->ibox.Top = dd->win->TopEdge;
if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME )
{
// changing the name does require closing and reopening
// of the window since the window size depends from the
// name... (and font)
CloseWindow( dd->win );
OpenWin( dd );
}
if( ((IPCMessage *) dd->messages)->command & (IPCCMD_BGC | IPCCMD_TC) )
{
BorderDraw( dd, FALSE );
}
if( ((IPCMessage *) dd->messages)->command & IPCCMD_HIDE )
{
SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_DISAPPEAR, dd->sender );
}
}
}
IPC_Reply( dd->messages );
}
return dd->stop;
}
/********************************************************************/
BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to )
{
FakeMsg *fmsg;
// create a fake CxMsg (not documented..., size is 232 bytes)
// and send it to the choosed CxObj
if( (fmsg = AllocMemH(mempool, 232)) )
{
fmsg->msg.mn_Node.ln_Type = NT_MESSAGE;
fmsg->msg.mn_Length = 232;
fmsg->Code = CXM_COMMAND;
fmsg->msg.mn_ReplyPort = reply_to;
fmsg->ID = type;
PutMsg( cxobj->cx_port, (struct Message *) fmsg );
return TRUE;
}
return FALSE;
}
/********************************************************************/
// saving/reading the config
// normally I use for this an own file, but since here is only to
// write some small values... :)
// the following include is only needed to use some defines of it
#include <libraries/iffparse.h>
// now we are doing some ID's
// each data block, which should be recognizeable must have an ID
// (=header)
#define DOE_ID MAKE_ID('D','O','E','X')
#define LEFT_TOP MAKE_ID('L','E','T','E')
#define COLOURS MAKE_ID('C','O','L','R')
#define NEW_NAME MAKE_ID('N','A','M','E')
BOOL WriteConfig( DOE_Data *dd )
{
APTR iffhandle;
ULONG size;
// open our config file for writing
if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_WRITE, DOE_ID)) )
{
// here you can see it is possible to write more than one value
// with one step, they must only follow each other...
IFFWriteChunk( iffhandle, &dd->win->LeftEdge, LEFT_TOP, sizeof(WORD) * 2 );
IFFWriteChunk( iffhandle, &dd->itext.FrontPen, COLOURS, sizeof(UBYTE) * 2 );
if( (size = strlen(dd->name)) )
{
// it's a nice idea to write the \0 of the string too,
// it does save us work on reading the data
IFFWriteChunk( iffhandle, dd->name, NEW_NAME, size + 1 );
}
IFFClose( iffhandle );
return 0;
};
return 1;
}
// also simple to understand...
BOOL ReadConfig( DOE_Data *dd )
{
APTR iffhandle;
ULONG nextchunk;
// open the config file for reading
if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_READ, DOE_ID)) )
{
// IFFNextChunk() does return the next ID (or NULL if there is none)
// and so we can switch here
while( (nextchunk = IFFNextChunk(iffhandle, 0)) )
{
switch( nextchunk )
{
case LEFT_TOP: IFFReadChunkBytes(iffhandle, &dd->ibox, sizeof(WORD) * 2 );
break;
case COLOURS : IFFReadChunkBytes(iffhandle, &dd->itext.FrontPen, sizeof(UBYTE) * 2 );
break;
case NEW_NAME: // if a string should be readed, it is needed to use the
// string alone in a chunk or at least to have it at the
// end of a structure - or -
// if you do this not, you must always write the whole
// structure
// if you try to read an alone written string, you
// must always set the size to read to the lenght of
// you string buffer
IFFReadChunkBytes(iffhandle, dd->name, 16 );
break;
};
};
IFFClose( iffhandle );
return 0;
};
return 1;
}